#ifdef HAVE_CONFIG_H
#  include <config.h>
#endif

#include <gnome.h>

#include <string.h>
#include <pthread.h>

#include "callbacks.h"
#include "interface.h"
#include "support.h"

#include "preamble.h"
GtkWidget *appMain;
pthread_t run_thread, show_thread; /* TODO: 多线程 */

void
on_new_file_activate (GtkMenuItem * menuitem, gpointer user_data)
{
  if (questionSave () == GNOME_OK)
    new ();
}


void
on_open_activate (GtkMenuItem * menuitem, gpointer user_data)
{
  if (questionSave () == GNOME_OK)
    gtk_widget_show (create_fileselectionOpen ());
}


void
on_save_activate (GtkMenuItem * menuitem, gpointer user_data)
{
  if (filename)
    {
      display (_("SAVE %s\n"), filename);
      writeto ();
      display (PROMPT);
    }
  else
    gtk_signal_emit_by_name (GTK_OBJECT
			     (lookup_widget
			      (GTK_WIDGET (appMain), "save_as")), "activate");
}


void
on_save_as_activate (GtkMenuItem * menuitem, gpointer user_data)
{
  gtk_widget_show (create_fileselectionSaveAs ());
  gtk_main ();
}


void
on_exit_activate (GtkMenuItem * menuitem, gpointer user_data)
{
  if (questionSave () == GNOME_OK)
    gtk_widget_destroy (appMain);	/* quit */
  else
    return;			/* no quit */
}


void
on_cut_activate (GtkMenuItem * menuitem, gpointer user_data)
{
  gtk_editable_cut_clipboard (GTK_EDITABLE
			      (lookup_widget
			       (GTK_WIDGET (menuitem), "textSourceProgram")));
}


void
on_copy_activate (GtkMenuItem * menuitem, gpointer user_data)
{
  gtk_editable_copy_clipboard (GTK_EDITABLE
			       (lookup_widget
				(GTK_WIDGET (menuitem),
				 "textSourceProgram")));
}


void
on_paste_activate (GtkMenuItem * menuitem, gpointer user_data)
{
  gtk_editable_paste_clipboard (GTK_EDITABLE
				(lookup_widget
				 (GTK_WIDGET (menuitem),
				  "textSourceProgram")));
}


void
on_clear_activate (GtkMenuItem * menuitem, gpointer user_data)
{
  GtkWidget *textSourceProgram;

  display (_("CLEAR\n"));
  textSourceProgram =
    lookup_widget (GTK_WIDGET (appMain), "textSourceProgram");
  gtk_text_freeze (GTK_TEXT (textSourceProgram));
  gtk_editable_delete_text (GTK_EDITABLE (textSourceProgram), 0, -1);
  gtk_text_thaw (GTK_TEXT (textSourceProgram));
  statusSaved = TRUE;
  display (PROMPT);
}


void
on_properties_activate (GtkMenuItem * menuitem, gpointer user_data)
{

}


void
on_preferences_activate (GtkMenuItem * menuitem, gpointer user_data)
{
  GtkStyle *defstyle;

  defstyle = gtk_widget_get_default_style ();
  SetStyleRecursively (lookup_widget (appMain, "textSourceProgram"), (gpointer) defstyle);	/* test code - set textSourceProgram defstyle */
}


void
on_about_activate (GtkMenuItem * menuitem, gpointer user_data)
{
  gtk_widget_show (create_about ());
}


void
on_buttonNew_clicked (GtkButton * button, gpointer user_data)
{
  gtk_signal_emit_by_name (GTK_OBJECT
			   (lookup_widget (GTK_WIDGET (appMain), "new_file")),
			   "activate");
}


void
on_ok_buttonOpen_clicked (GtkButton * button, gpointer user_data)
{
  GtkWidget *fileselectionOpen =
    lookup_widget (GTK_WIDGET (button), "fileselectionOpen");
  gchar *fn;

  fn =
    gtk_file_selection_get_filename (GTK_FILE_SELECTION (fileselectionOpen));
  if (filename)
    g_free (filename);
  filename = g_strdup (fn);
  gtk_widget_destroy (fileselectionOpen);
  load ();
}


void
on_textSourceProgram_changed (GtkEditable * editable, gpointer user_data)
{
  if (statusSaved == TRUE)
    {
      statusSaved = FALSE;
      change_title ();
    }
  statusAssembled = FALSE;
}


void
on_ok_buttonSaveAs_clicked (GtkButton * button, gpointer user_data)
{
  GtkWidget *fileselectionSaveAs =
    lookup_widget (GTK_WIDGET (button), "fileselectionSaveAs");
  gchar *fn;
  /* get file name */
  fn =
    gtk_file_selection_get_filename (GTK_FILE_SELECTION
				     (fileselectionSaveAs));
  if (filename)
    g_free (filename);
  filename = g_strdup (fn);
  display (_("SAVE AS %s\n"), filename);
  statusSaved = TRUE;
  change_title ();
  writeto ();
  display (PROMPT);
  gtk_widget_destroy (fileselectionSaveAs);
}


void
on_clear_screen_activate (GtkMenuItem * menuitem, gpointer user_data)
{
  GtkWidget *textScreen;

  textScreen = lookup_widget (GTK_WIDGET (appMain), "textScreen");
  gtk_text_freeze (GTK_TEXT (textScreen));
  gtk_editable_delete_text (GTK_EDITABLE (textScreen), 0, -1);
  display (PROMPT);
  gtk_text_thaw (GTK_TEXT (textScreen));
}


void
on_assemble_activate (GtkMenuItem * menuitem, gpointer user_data)
{
  GtkWidget *textSourceProgram;
  char *source;

  display (_("ASSEMBLE\n"));

  textSourceProgram =
    lookup_widget (GTK_WIDGET (appMain), "textSourceProgram");
  source =
    gtk_editable_get_chars (GTK_EDITABLE (textSourceProgram), 0,
			    gtk_text_get_length (GTK_TEXT
						 (textSourceProgram)));

  assemble (source);

  showState ();
  display (PROMPT);
}


void
on_run_activate (GtkMenuItem * menuitem, gpointer user_data)
{
  if (!statusAssembled)
    gtk_signal_emit_by_name (GTK_OBJECT
			     (lookup_widget
			      (GTK_WIDGET (appMain), "assemble")),
			     "activate");
  display (_("RUN\n"));

  /* TODO: 使用多线程或gtk_main() */
#if 1
  run ();
#else
  pthread_create (&run_thread, NULL, (void *) run, NULL);
  pthread_create (&show_thread, NULL, (void *) show, NULL);
#endif

  showState ();			/* show state */
  display (PROMPT);
}


void
on_step_activate (GtkMenuItem * menuitem, gpointer user_data)
{
  GtkWidget *textSourceProgram =
    lookup_widget (GTK_WIDGET (appMain), "textSourceProgram");
  int i, j, start, end;
  extern SENTENCE *sentences;

  if (!statusAssembled)
    gtk_signal_emit_by_name (GTK_OBJECT
			     (lookup_widget
			      (GTK_WIDGET (appMain), "assemble")),
			     "activate");
  display (_("STEP\n"));

  i = step ();
  if (i >= 0)
    {
      start = 0;
      for (j = 0; j < i; j++)
	start += cc_strlen (sentences[j].string) + 1;
      end = start + cc_strlen (sentences[i].string) + 1;

      gtk_editable_set_position (GTK_EDITABLE
				 (lookup_widget
				  (GTK_WIDGET (appMain),
				   "textSourceProgram")), start);

      gtk_editable_select_region (GTK_EDITABLE (textSourceProgram), start,
				  end);
    }
  else
    gtk_editable_set_position (GTK_EDITABLE (textSourceProgram), 0);

  showState ();			/* show state */

  display (PROMPT);
}


void
on_trace1_activate (GtkMenuItem * menuitem, gpointer user_data)
{
  int i, j, start, end;
  extern SENTENCE *sentences;

  if (!statusAssembled)
    gtk_signal_emit_by_name (GTK_OBJECT
			     (lookup_widget
			      (GTK_WIDGET (appMain), "assemble")),
			     "activate");
  display (_("TRACE\n"));

  i = trace ();
  if (i >= 0)
    {
      start = 0;
      for (j = 0; j < i; j++)
	start += cc_strlen (sentences[j].string) + 1;
      end = start + cc_strlen (sentences[i].string) + 1;
      gtk_editable_set_position (GTK_EDITABLE
				 (lookup_widget
				  (GTK_WIDGET (appMain),
				   "textSourceProgram")), start);

      gtk_editable_select_region (GTK_EDITABLE
				  (lookup_widget
				   (GTK_WIDGET (appMain),
				    "textSourceProgram")), start, end);
    }
  else
    gtk_editable_set_position (GTK_EDITABLE
			       (lookup_widget
				(GTK_WIDGET (appMain), "textSourceProgram")),
			       0);

  showState ();			/* show state */
  display (PROMPT);
}


void
on_font_activate (GtkMenuItem * menuitem, gpointer user_data)
{
  GtkStyle *style;
  GtkStyle *defstyle;
  GdkFont *font;
  gchar *szFont;

  /* --- Call the font dialog to get a font --- */
  if ((szFont = GetFont ()) == NULL)
    return;
  if ((font = gdk_font_load (szFont)) == NULL)
    return;
  g_free (szFont);

  /* a style with the new font */
  /* --- Get the default style --- */
  defstyle = gtk_widget_get_default_style ();

  /* --- Make a copy of it. --- */
  style = gtk_style_copy (defstyle);

  style->font = font;

  /* --- Set the style of the wiget based on that new style */
  SetStyleRecursively (lookup_widget (appMain, "textSourceProgram"),
		       (gpointer) style);
}


void
Quit (GtkObject * object, gpointer user_data)
{
  gtk_main_quit ();
}


void
on_ok_buttonFont_clicked (GtkButton * button, gpointer user_data)
{
  GtkWidget *fontselectiondialog = GTK_WIDGET (user_data);

  /* --- Get the font name --- */
  szFontName =
    gtk_font_selection_dialog_get_font_name (GTK_FONT_SELECTION_DIALOG
					     (fontselectiondialog));
  gtk_widget_destroy (fontselectiondialog);
}


void
on_continue_activate (GtkMenuItem * menuitem, gpointer user_data)
{
  display (_("CONTINUE\n"));

  cont ();

  showState ();			/* show state */
  display (PROMPT);
}


gboolean
on_appMain_delete (GtkWidget * widget, GdkEvent * event, gpointer user_data)
{
  if (questionSave () == GNOME_OK)
    return FALSE;		/* quit */
  else
    return TRUE;		/* no quit */
}


void
on_buttonOpen_clicked (GtkButton * button, gpointer user_data)
{
  gtk_signal_emit_by_name (GTK_OBJECT
			   (lookup_widget (GTK_WIDGET (appMain), "open")),
			   "activate");
}


void
on_buttonSave_clicked (GtkButton * button, gpointer user_data)
{
  gtk_signal_emit_by_name (GTK_OBJECT
			   (lookup_widget (GTK_WIDGET (appMain), "save")),
			   "activate");
}


void
on_buttonCut_clicked (GtkButton * button, gpointer user_data)
{
  gtk_signal_emit_by_name (GTK_OBJECT
			   (lookup_widget (GTK_WIDGET (appMain), "cut")),
			   "activate");
}


void
on_buttonCopy_clicked (GtkButton * button, gpointer user_data)
{
  gtk_signal_emit_by_name (GTK_OBJECT
			   (lookup_widget (GTK_WIDGET (appMain), "copy")),
			   "activate");
}


void
on_buttonPaste_clicked (GtkButton * button, gpointer user_data)
{
  gtk_signal_emit_by_name (GTK_OBJECT
			   (lookup_widget (GTK_WIDGET (appMain), "paste")),
			   "activate");
}


void
on_buttonAssemble_clicked (GtkButton * button, gpointer user_data)
{
  gtk_signal_emit_by_name (GTK_OBJECT
			   (lookup_widget (GTK_WIDGET (appMain), "assemble")),
			   "activate");
}


void
on_buttonRun_clicked (GtkButton * button, gpointer user_data)
{
  gtk_signal_emit_by_name (GTK_OBJECT
			   (lookup_widget (GTK_WIDGET (appMain), "run")),
			   "activate");
}


void
on_buttonStep_clicked (GtkButton * button, gpointer user_data)
{
  gtk_signal_emit_by_name (GTK_OBJECT
			   (lookup_widget (GTK_WIDGET (appMain), "step")),
			   "activate");
}

void
on_stop1_activate (GtkMenuItem * menuitem, gpointer user_data)
{
  reg.PC = end_PC;

/* TODO: 多线程或gtk_main()循环 */
#if 0
  pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS,NULL);
  if (pthread_cancel(run_thread)!=0)
    puts("run thread do not cancel");
  if (pthread_cancel(show_thread)!=0)
    puts("show thread do not cancel");
#endif
}


void
on_show1_activate (GtkMenuItem * menuitem, gpointer user_data)
{
  showState ();
}


void
on_indent1_activate (GtkMenuItem * menuitem, gpointer user_data)
{
  GtkWidget *textSourceProgram;
  char *src, *dest;
  int len;

  display (_("INDENT\n"));

  textSourceProgram =
    lookup_widget (GTK_WIDGET (appMain), "textSourceProgram");
  len = gtk_text_get_length (GTK_TEXT (textSourceProgram));
  src = gtk_editable_get_chars (GTK_EDITABLE (textSourceProgram), 0, len);

  if ((dest = (char *) malloc (sizeof (char) * (len + 1))) != NULL)
    {
      indent (src, dest);

      gtk_text_freeze (GTK_TEXT (textSourceProgram));
      gtk_editable_delete_text (GTK_EDITABLE (textSourceProgram), 0, -1);
      gtk_text_insert (GTK_TEXT (textSourceProgram), NULL, NULL, NULL, dest,
		       strlen (dest));
      gtk_text_thaw (GTK_TEXT (textSourceProgram));

      free (dest);		/* TODO: 死机 */
    }
  else
    display (_("Memory is not enough.\n"));

  free (src);

  display (PROMPT);
}


void
on_casl1_activate (GtkMenuItem * menuitem, gpointer user_data)
{
  GtkWidget *dialogCASL = create_dialogCASL ();
  GtkWidget *lessCASL = lookup_widget (dialogCASL, "lessCASL");
  char *helpfile = gnome_config_get_string ("/gcasl/CASL");

  if (helpfile == NULL)
    helpfile = DOC_DIR"CASL";
  gnome_less_show_file (GNOME_LESS (lessCASL), helpfile);

  gtk_widget_show (dialogCASL);
}


void
on_buttonCASL_OK_clicked (GtkButton * button, gpointer user_data)
{
  GtkWidget *dialogCASL = lookup_widget (GTK_WIDGET (button), "dialogCASL");

  gtk_widget_destroy (dialogCASL);
}



void
on_exam_library1_activate (GtkMenuItem * menuitem, gpointer user_data)
{
  GtkWidget *dialogExamlib = create_dialogExamlib ();
  GtkWidget *list = lookup_widget (GTK_WIDGET (dialogExamlib), "listExamlib");

  int i;

  extern structEInfo examlib_info[];
  extern char *examlib_title;
  extern int examlib_number;

  if (examlib_information ())
    {
      //      gtk_window_set_title (GTK_WINDOW (dialogExamlib), examlib_title);

      for (i = 0; i < examlib_number; i++)
	{
	  GtkWidget *item;

	  item = gtk_list_item_new_with_label (examlib_info[i].name);
	  gtk_widget_show (item);

	  gtk_container_add (GTK_CONTAINER (list), item);

	  gtk_signal_connect (GTK_OBJECT (item), "select",
			      GTK_SIGNAL_FUNC
			      (on_listExamlib_selection_changed),
			      examlib_info[i].name);
	}
      gtk_widget_show_all (dialogExamlib);
    }
}


void
on_fill_answer1_activate (GtkMenuItem * menuitem, gpointer user_data)
{
  GtkWidget *textSourceProgram =
    lookup_widget (GTK_WIDGET (appMain), "textSourceProgram");
  char *answer;

  if ((answer = examlib_answer ()) != NULL)
    {
      display (_("FILL ANSWER\n#"));

      gtk_text_freeze (GTK_TEXT (textSourceProgram));
      gtk_editable_delete_text (GTK_EDITABLE (textSourceProgram), 0, -1);
      gtk_text_insert (GTK_TEXT
		       (textSourceProgram), NULL,
		       NULL, NULL, answer, strlen (answer));
      gtk_editable_set_position (GTK_EDITABLE (textSourceProgram), 0);
      gtk_text_thaw (GTK_TEXT (textSourceProgram));

      free (answer);
    }
}


void
on_buttonOK_clicked (GtkButton * button, gpointer user_data)
{
  GtkWidget *textSourceProgram =
    lookup_widget (GTK_WIDGET (appMain), "textSourceProgram");
  GtkWidget *dialogExamlib =
    lookup_widget (GTK_WIDGET (button), "dialogExamlib");
  char *question;
  extern structEInfo examlib_info[];
  extern int examlib_no;

  if ((question = examlib_question ()) != NULL)
    {
      display (_("LOAD EXAM \"%s\"\n#"),examlib_info[examlib_no].name);

      gtk_text_freeze (GTK_TEXT (textSourceProgram));
      gtk_editable_delete_text (GTK_EDITABLE (textSourceProgram), 0, -1);
      gtk_text_insert (GTK_TEXT
		       (textSourceProgram), NULL,
		       NULL, NULL, question, strlen (question));
      gtk_editable_set_position (GTK_EDITABLE (textSourceProgram), 0);
      gtk_text_thaw (GTK_TEXT (textSourceProgram));

      free (question);
    }

  gtk_widget_destroy (dialogExamlib);
}


void
on_buttonCancel_clicked (GtkButton * button, gpointer user_data)
{
  GtkWidget *dialogExamlib =
    lookup_widget (GTK_WIDGET (button), "dialogExamlib");

  gtk_widget_destroy (dialogExamlib);
}


void
on_listExamlib_selection_changed (GtkList * list, gpointer user_data)
{
  examlib_no_set ((char *) user_data);
}
/*-------------------------------The End-------------------------*/
